import * as step from '@flow-step/step-toolkit'
import dockerToolkit from '@flow-step/dockertoolkit'
import {IParams} from './params';
import {copyFileSync, existsSync, readFileSync} from 'fs';
import {join} from 'path';
import {generateOptionsArray} from "./util";

export async function buildPushImage(params: IParams): Promise<void> {
    const projectDir = params.projectDir;
    process.chdir(projectDir);

    const dockerfilePath = params.dockerfilePath;
    let contextPath = params.contextPath
    contextPath = dockerToolkit.formatContextPath(contextPath, dockerfilePath, projectDir);
    step.info(`contextPath is set to: ${contextPath}`);

    const dockerfileContent = readFileSync(dockerfilePath, 'utf-8');
    step.info(`-----------Dockerfile Content----------\n${dockerfileContent}-----------Dockerfile Content----------`)

    let image = dockerToolkit.parseImage(params.image);
    step.info(`docker image is set to: ${image}`)

    const dockerTag = dockerToolkit.getTagFromImageId(image)
    if (dockerTag === "") { throw new Error(`parse docker tag err, invalid image id: ${image}`) }
    step.info(`docker tag is set to: ${dockerTag}`)

    let cacheType = params.cacheType;
    if (cacheType === undefined) { cacheType = "remote" }
    let args = dockerToolkit.getDockerBuildArgs(image, dockerfilePath, contextPath, cacheType, params.cacheImageId as string);
    const options = params.options as string
    if (options) {
        const optionsArray = generateOptionsArray(options);
        args = args.concat(optionsArray)
    }

    step.info(`ready to execute: docker ${args.join(" ")}`)
    const resultCode = await executeWithMaxRetryThreeTimes(args);
    if (resultCode !== 0) {
        throw new Error(`build image failed, exit code: ${resultCode}`);
    }


    // export docker artifact for gui
    const imageArtifact = new step.artifact.ArtifactDocker({
        artifact: "image",
        image: image,
        dockerTag: dockerTag
    });
    step.artifact.exportArtifactDocker(`${params.stepID}.image`, imageArtifact);

    // export docker artifact for pac
    if (params.artifact) {
        const imageArtifactPAC = new step.artifact.ArtifactDocker({
            artifact: `${params.artifact}`,
            image: image,
            dockerTag: dockerTag
        });
        step.artifact.exportArtifactDocker(`${params.stepID}.artifact`, imageArtifactPAC);
    }
}

export async function executeWithMaxRetryThreeTimes(args: string[]): Promise<number> {
    const maxRetries = 3;
    let retryCount = 0;

    while (retryCount < maxRetries) {
        let retryAble = false;
        const resultCode = await step.exec.call('docker', args, {
            listener: {
                stdoutLine: (line: string) => step.info(line),
                stderrLine: (line: string) => {
                    step.info(line);
                    // hack for retry
                    if (line === 'ERROR: failed to receive status: rpc error: code = Canceled desc = context canceled') {
                        retryCount++; retryAble = true;
                    }
                },
            }
        });

        if (!retryAble) {
            return resultCode;
        } else if (retryCount < maxRetries) {
            step.warning(`Retrying... Attempt ${retryCount}`);
            continue
        }

        return resultCode;
    }

    throw new Error(`Failed after ${maxRetries} attempts`);
}
